Using Psalm and PhpStorm for realtime static analysis

Building on the static analysis of Phan, I’ve also recently started using Psalm, a PHP static analyzer from Vimeo’s engineering team. What I particularly love about Psalm is its realtime analysis and integration within PhpStorm. Instead of needing to run a report after any changes, Psalm can highlight issues as they happen with my source code open.

While Psalm includes the necessary language server to integrate with PhpStorm, a plugin is needed to make the connection. I’m using the LSP Support plugin by Guillaume Tâche. Here’s what I did to get everything setup, and some lessons I learned along the way.

Getting Set Up

First, Install Psalm via composer:

composer require --dev vimeo/psalm

Then setup a psalm.xml configuration file. Psalm provides 8 levels of strictness, 1 being the most strict and 3 being the default. I’m using level 4.

./vendor/bin/psalm --init [source_directory=src] [config_level=3]

Next, I have a few of my own helper functions, so I added stubs to those functions inside the psalm.xml. I also use New Relic, and JetBrains helpfully provides a repo that contains pre-defined stubs for numerous libraries.

    <stubs>
        <file name="../phpstorm-stubs/newrelic/newrelic.php"/>
        <file name="../phpstorm-stubs/funnel-cake/funnel-cake.php"/>
    </stubs>

At this point Psalm is installed and configured – now let’s get some static analysis goodness from it!

Using Psalm

To see Psalm’s analysis in your console, you’ll only need to run psalm from the same directory as your psalm.xml. For some reason for me, I was getting corrupt caches (I think from running psalm while the language server is setup, which i’ll explain below), so I run from the command line with:

psalm --no-progress --no-cache

I’ve setup an External Tool in PhpStorm to run the above, which will show its output from inside of PhpStorm. I’ve actually setup a short script to better format Psalm’s output. PhpStorm needs absolute file paths, and can then link directly to the issue. Save the following script as run_psalm.sh in the root directory of your project:

psalm --no-progress --no-cache > psalm.out

cat psalm.out | sed G | sed -E 's|(.*) - ([a-zA-Z0-9 _\./\-]+:[[:digit:]]+)|'"$(pwd)"'/\2\
\1|g' | perl -pi -0 -w -e 's/\n\n/\n/g'

rm psalm.out

Then, in PhpStorm, open up External Tools in the Preferences window:

Preferences → Tools → External Tools

Then, add a new external tool and fill in the details to run the above script:

The Output filter will allow PhpStorm to auto-link issues from Psalm’s output.

I’ve also setup an External Tool for Phan, as I’ve described before, so my Tools → External Tools menu shows both Phan and Psalm options now:

But this is only the first integration – the next one is what’s got me most excited about Psalm – full IDE integration for realtime highlighting of issues.

Language Server Plugin

To get realtime analysis, open up PhpStorm’s plugin marketplace and search for “LSP Support” and you’ll find the plugin by gtache.

After installing the plugin and restarting PhpStorm, you’ll see a new menu in the Languages & Frameworks section of preference window. Open the Server Definitions section.

Preferences → Languages & Frameworks → Language Server Protocol → Server Definitions

Set the first drop down it Executable, and set the Extension to php. For the path, set it to the path of your php executable. I’m running MAMP, I’ve set my path to /Applications/MAMP/bin/php/php7.3.8/bin/php. Last, set the args to vendor/bin/psalm-language-server.

Your configuration should look something like this when you’re done:

Restart PhpStorm, open a php file, and if everything goes well you should see the language server icon show the start up success and see the green status icon in the footer.

Now you should be seeing live Psalm feedback inside of PhpStorm!

It’s Not Perfect

There’s a few odd things I’ve noticed when using the language server, here’s a few:

  1. It doesn’t seem to start until I’ve edited a file. After opening a file, nothing will highlight until i’ve typed at least 1 character into the editor, but then everything will pop in.
  2. Sometimes it’s slow. I think it re-analyzes after every keystroke, and I wish the LSP Plugin would be a bit gentler here
  3. I’ve received occasional crashes of the LSP Support plugin. It’s rare enough that it’s not a huge problem, but is a bit of an inconvenience.
  4. The plugin overwrites the Quick Documentation mouse click with its own popover. I’ve set option+click to open the Quick Documentation window, but instead it was opening the LSP information.
Here’s the default Quick Documentation that I want….
But here’s the Quick Documentation override in the LSP Plugin

Customizing the LSP Plugin

Because of the crashes I ran into, and the fact that I really liked the older Quick Documentation more than the LSP documentation, I decided to try and customize the plugin just a bit to see if I could change that.

You can find the full source of the LSP Plugin on GitHub: https://github.com/gtache/intellij-lsp. And I’ve forked the code to remove the Quick Documentation override: https://github.com/adamwulf/intellij-lsp/tree/feature/remove-quickdoc. I’ve also fixed some of the crashes I’ve run into, but not all of them.

To build from my fork:

git clone git@github.com:adamwulf/intellij-lsp.git
git checkout feature/remove-quickdoc
./gradlew buildPlugin

That will generate a build/distributions/LSP Support.zip file that you can install into PhpStorm. To install, open the Plugins section, click the gear, and choose Install From Disk, select the .zip file, and away you go.

Choose build/distributions/LSP Support.zip to install the custom build.

Conclusion

After learning more about Psalm and its PhpStorm intonations, I now have:

  1. Realtime analysis for any option files using the LSP Support plugin
  2. Full project analysis using the External Tools menu option
  3. A custom LSP plugin for ultimate nerd customization

Links

1 thought on “Using Psalm and PhpStorm for realtime static analysis

  1. Your run_psalm.sh to convert the file paths used to work great, but suddenly doesn’t anymore – I’m assuming psalm changed it’s output somehow and I’m failing to adjust the regex to it. Any help?

Leave a Reply

Your email address will not be published. Required fields are marked *